﻿namespace LaoLuo.Time
{
    using System;
    using System.Collections.Generic;
    using System.Linq;

    /// <summary>
    /// 提供一个周为基本单位的时间表的操作
    /// </summary>
    public class WeeklyTimetable
    {
        /// <summary>
        /// 时间表中的时间片段
        /// </summary>
        readonly List<WeeklyTimePeriod> periods = new List<WeeklyTimePeriod>();

        /// <summary>
        /// 初始化一个WeeklyTimetable
        /// </summary>
        /// <param name="periods">时间片段</param>
        public WeeklyTimetable(params WeeklyTimePeriod[] periods)
            : this(periods.AsEnumerable())
        {
            
        }

        /// <summary>
        /// 初始化一个WeeklyTimetable
        /// </summary>
        /// <param name="periods">时间片段</param>
        public WeeklyTimetable(IEnumerable<WeeklyTimePeriod> periods)
        {
            foreach (var item in periods.OrderBy(i => i.EndPoint.Weight))
            {
                this.periods.Add(item);
            }
        }

        /// <summary>
        /// 获取时间表中包含此时间点的时间片段
        /// </summary>
        /// <param name="point">时间点</param>
        /// <returns>如果获取了包含此时间点的时间片段,则返回,否则返回null</returns>
        public WeeklyTimePeriod? GetParentPeriodOrDefault(WeeklyTimePeriod.WeeklyTimePoint point)
        {
            foreach (var item in this.periods)
            {
                if (item.HasPoint(point))
                {
                    return item;
                }
            }

            return null;
        }

        /// <summary>
        /// 如果有包含指定时间点的时间片段则返回,否则返回距离时间点最近的且在时间点之前的时间片段
        /// </summary>
        /// <param name="point">时间点</param>
        /// <param name="pointIsInPeriod">时间点是否在返回的时间片段内</param>
        /// <returns>合适的时间片段</returns>
        public WeeklyTimePeriod GetProperPeriod(WeeklyTimePeriod.WeeklyTimePoint point, out bool pointIsInPeriod)
        {
            pointIsInPeriod = false;

            for (int i = 0; i < this.periods.Count; i++)
            {
                if (this.periods[i].EndPointIsAfter(point))
                {
                    if (this.periods[i].StartPointIsBefore(point))
                    {
                        pointIsInPeriod = true;

                        return this.periods[i];
                    }

                    if (i == 0)
                    {
                        break;
                    }

                    return this.periods[i - 1];
                }
            }

            var ret = this.periods.Last();

            point.Weight += WeeklyTimePeriod.WeeklyTimePoint.ModWeight;

            pointIsInPeriod = ret.HasPoint(point);

            return ret;
        }

        /// <summary>
        /// 如果有包含指定时间点的时间片段则返回,否则返回距离时间点最近的且在时间点之前的时间片段
        /// </summary>
        /// <param name="point">时间点</param>
        /// <param name="pointIsInPeriod">时间点是否在返回的时间片段内</param>
        /// <returns>合适的时间片段</returns>
        public DateTime[] GetProperPeriod(DateTime point, out bool pointIsInPeriod)
        {
            var period = GetProperPeriod(new WeeklyTimePeriod.WeeklyTimePoint(point.DayOfWeek, point.Hour, point.Minute, point.Second), out pointIsInPeriod);

            DateTime ret0 = period.StartPoint.GetDateTime(point.AddDays(0));
            DateTime ret1 = period.EndPoint.GetDateTime(point.AddDays(7));

            if ((ret1 - ret0).TotalDays > 7)
            {
                ret1 = ret1.AddDays(-7);
            }

            //if (period.StartPoint > period.EndPoint)
            //{

            //}

            return new DateTime[2] { ret0, ret1 };
        }
    }
}
